//
//  ipv4_parser.cpp
//  testpcap
//
//  Created by bugforever on 1/14/15.
//  Copyright (c) 2015 bugforever. All rights reserved.
//

#include "ipv4_parser.h"
#include "string.h"

/* ipv4 header */
typedef struct ipv4_header {
    u_char ver_ihl;         /* version and ip header length */
    u_char tos;             /* type of service */
    u_short tlen;           /* total length */
    u_short identification; /* identification */
    u_short flags_fo;       // flags and fragment offset
    u_char ttl;             /* time to live */
    u_char proto;           /* protocol */
    u_short crc;            /* header checksum */
    u_char saddr[4];       /* source address */
    u_char daddr[4];       /* destination address */
    u_int op_pad;           /* option and padding */
}ipv4_header;

ipv4_parser::ipv4_parser()
{
    ;
}

ipv4_parser::~ipv4_parser()
{
    ;
}

ipv4_data * ipv4_parser::parse(  network_ethernet_data * ptr_ethernet_data )
{
    if (ptr_ethernet_data->ether_type != ETHERTYPE_IPV4)
    {
        switch( ptr_ethernet_data->ether_type )
        {
            case ETHERTYPE_ARP:
                printf( "%s\n" , "ARP" );
                break;
            case ETHERTYPE_RARP:
                printf( "%s\n" , "RARP" );
                break;
            case ETHERTYPE_IPV6:
                printf( "%s\n" , "IPV6" );
                break;
            default:
                printf( "Unknown %d\n" , ptr_ethernet_data->ether_type );
                
        }
        return 0;
    }
    
    ipv4_header * ptr_ip = (ipv4_header *)ptr_ethernet_data->ptr_data->get_data_by_tag(NDT_ETHERNET_DATA);
    
    m_ipv4.version = (ptr_ip->ver_ihl & 0xf0)>>4;
    
    m_ipv4.total_length = ntohs(ptr_ip->tlen);
    m_ipv4.header_length = (ptr_ip->ver_ihl & 0xf) * 4;
    
    m_ipv4.identification = ntohs(ptr_ip->identification);
    
    memcpy( m_ipv4.saddr , ptr_ip->saddr , 4 );
    memcpy( m_ipv4.daddr , ptr_ip->daddr , 4 );
    
    m_ipv4.ttl = ptr_ip->ttl;
    
    m_ipv4.protocol = ptr_ip->proto;
    
    if( ntohs(ptr_ip->flags_fo) & 0x4000 )
        m_ipv4.will_fragment = false;
    else
        m_ipv4.will_fragment = true;
    
    if( ntohs(ptr_ip->flags_fo) & 0x2000 )
        m_ipv4.is_last_fragment = false;
    else
        m_ipv4.is_last_fragment = true;
    
    m_ipv4.fragment_offset = ( ntohs(ptr_ip->flags_fo) & 0x1fff ) * 8 ;
    m_ipv4.ptr_data = ptr_ethernet_data->ptr_data;
    m_ipv4.ptr_data->set_tag( NDT_IP_DATA , m_ipv4.ptr_data->get_offset_by_tag( NDT_ETHERNET_DATA ) + m_ipv4.header_length );
    
    return &m_ipv4;
}











